﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System;

public class DepthTextureTool : EditorWindow
{


    int selectedSize = 256;
    string[] names = new string[] {  "256","128", "512","1024" };
    int[] sizes = { 256, 128, 512, 1024 };

    Shader baseShader;
    RenderTexture pervew ;
    RenderTexture sceneDepth;
    static List<int> layerNumbers = new List<int>();
    float farClip = 10f;
    bool debug = false;
    static LayerMask LayerMaskField(string label, LayerMask layerMask)
    {
        var layers = InternalEditorUtility.layers;

        layerNumbers.Clear();

        for (int i = 0; i < layers.Length; i++)
            layerNumbers.Add(LayerMask.NameToLayer(layers[i]));

        int maskWithoutEmpty = 0;
        for (int i = 0; i < layerNumbers.Count; i++)
        {
            if (((1 << layerNumbers[i]) & layerMask.value) > 0)
                maskWithoutEmpty |= (1 << i);
        }

        maskWithoutEmpty = UnityEditor.EditorGUILayout.MaskField(label, maskWithoutEmpty, layers);

        int mask = 0;
        for (int i = 0; i < layerNumbers.Count; i++)
        {
            if ((maskWithoutEmpty & (1 << i)) > 0)
                mask |= (1 << layerNumbers[i]);
        }
        layerMask.value = mask;

        return layerMask;
    }
    MeshRenderer render  ;
    Camera cam;
    LayerMask layerMask = -1;
    // Add menu named "My Window" to the Window menu
    [MenuItem("Window/小工具/水深度图生成")]
    static void Init()
    {
        // Get existing open window or if none, make a new one:
        DepthTextureTool window = (DepthTextureTool)EditorWindow.GetWindow(typeof(DepthTextureTool));
        window.Show();
    }

    void OnGUI()
    {

        EditorGUI.BeginChangeCheck();
        render = (MeshRenderer)EditorGUILayout.ObjectField("Obj:", render, typeof(MeshRenderer),true);
        if (EditorGUI.EndChangeCheck())
        {
            if (null != render)
            {
                baseShader = render.sharedMaterial.shader;
            }
            
        }
        layerMask = LayerMaskField("Scene layer",layerMask);
        selectedSize = EditorGUILayout.IntPopup("Resize Scale: ", selectedSize, names, sizes);
        farClip = EditorGUILayout.Slider(farClip, 1f, 100f);
        debug = EditorGUILayout.Toggle("debug:",debug);
        EditorGUI.BeginDisabledGroup(render==null);
        bool m = GUILayout.Button("Make");
        
        EditorGUI.EndDisabledGroup();
        if (null != sceneDepth&& debug)
        {
            int width = (int)this.position.width - 10;
            width = 256;
            Rect r = EditorGUILayout.GetControlRect(GUILayout.Width(width), GUILayout.Height(width));
            EditorGUI.DrawPreviewTexture(r, sceneDepth);
        }

        if (null != pervew)
        {
            int width = (int)this.position.width - 10;
            width = 256;
            Rect r = EditorGUILayout.GetControlRect(GUILayout.Width(width), GUILayout.Height(width));
            EditorGUI.DrawPreviewTexture(r, pervew);
        }



        if (render != null)
        {
            MakeDepthTex();
        }
        if (m)
        {
            string path = EditorUtility.SaveFilePanelInProject("", "t", "png", "");
            if (path.Length > 0)
            {
                SaveTexture( path,pervew);
            }
            
        }
    }

    private void SaveTexture(string path,RenderTexture pervew)
    {
        Texture2D t = new Texture2D(pervew.width, pervew.height,TextureFormat.R16,true);
        var old = RenderTexture.active;
        RenderTexture.active = pervew;
        t.ReadPixels(new Rect(0, 0, t.width, t.height), 0, 0);

        t.Apply();
        RenderTexture.active = old;
        System.IO.File.WriteAllBytes(path, t.EncodeToPNG());
        AssetDatabase.ImportAsset(path);
    }

    Shader depthShader;
    Shader depthBackShader;
    void MakeDepthTex()
    {
        if (null == cam)
        {
            GameObject g = new GameObject("Camera");
            cam = g.AddComponent<Camera>();
        }
        cam.hideFlags = HideFlags.HideAndDontSave;
        cam.orthographic = true;
        var bounds = render.bounds;
        cam.clearFlags = CameraClearFlags.SolidColor;
        cam.backgroundColor = Color.black;
        var t = render.transform.position;
        var size = bounds.size;
        cam.nearClipPlane = 0f;
        cam.farClipPlane = farClip+0.2f;
        float w = Mathf.Max(size.x, size.z);
        w *= 0.501f;
        cam.orthographicSize = w;
        cam.transform.forward = Vector3.down;
        cam.transform.position = bounds.center + Vector3.up * (size.y * 0.5f+0.1f);

        if (null != pervew&&pervew.width != selectedSize)
        {
            GameObject.DestroyImmediate(pervew,true);
            pervew = null;

        }
        if (null == pervew)
            pervew = new RenderTexture(selectedSize, selectedSize, 0, RenderTextureFormat.RHalf);
        if (null == sceneDepth)
        {
            sceneDepth = new RenderTexture(2048, 2048, 32,RenderTextureFormat.RHalf);
        }
        if (null == depthShader)
        {
            depthShader = Shader.Find("Hidden/DepthFormOrthoCam");
        }
        if (null == depthBackShader)
        {
            depthBackShader = Shader.Find("Hidden/BakeDepth");
        }
        cam.targetTexture = sceneDepth;
        cam.cullingMask = layerMask;
        cam.enabled = false;
        render.enabled = false;
        cam.SetReplacementShader(depthShader, null);
        cam.Render();

        cam.targetTexture = pervew;
        cam.ResetReplacementShader();
        cam.cullingMask = -1;
        cam.SetReplacementShader(depthBackShader, "RenderType");
        render.enabled = true;
        Shader.SetGlobalTexture("_CustomBakeDepthTex", sceneDepth);
       
        //_DepthTex
        baseShader = render.sharedMaterial.shader;
        render.sharedMaterial.shader = depthBackShader;
        cam.Render();
        render.sharedMaterial.shader = baseShader;
        sceneDepth.DiscardContents();

        
        //cam.worldToCameraMatrix;

         

        //selectedSize
    }

    private void OnDisable()
    {
        if (null != cam)
        {
            GameObject.DestroyImmediate(cam.gameObject, true);
        }
        if (null != pervew)
        {
            GameObject.DestroyImmediate(pervew,true);
        }
        if (null != sceneDepth)
        {
            GameObject.DestroyImmediate(sceneDepth, true);
        }
    }
}

 